﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.IO;
using System.Text.RegularExpressions;
//using Barcode.DataMatrix;
using System.Drawing.Imaging;
using AForge.Math;

namespace MagicCube_v2_Demo
{
    public partial class Form1 : Form
    {

        /**********************************************
         * 定义常量
         * ********************************************/
        public const int BLOCKS_SIDE_LEN = 16;       //图像分块后每块的边长
        public const int IMAGE_SIDE_LEN = 512;      //图像的边长（正方形）
        public static int num = IMAGE_SIDE_LEN / BLOCKS_SIDE_LEN;


        /*************************************************
         * 定义变量
         * **********************************************/
        public  Bitmap bmpSourceImage;
        public string strSourceImage;
        public double[] dInfo = new double[IMAGE_SIDE_LEN];
        public Bitmap bmpInsertedImage;
        byte[,] bBmpBlocks = new byte[num * num, BLOCKS_SIDE_LEN * BLOCKS_SIDE_LEN];
        Complex[,] cpxBmpBlocks = new Complex[num * num, BLOCKS_SIDE_LEN * BLOCKS_SIDE_LEN];
        public double[] dGetInfo = new double[22*22];
        public Bitmap bmpDM;
        public byte[] bCompare1;
        public byte[] bCompare2;
        public int[] bCompared;
        public Bitmap bmpGetDM;
        string sBarcode;


       
        /*******************************************************/
        public Form1()
        {
            InitializeComponent();
        }


        //打开图片
        private void btnOpenImage_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofdSourceImage = new OpenFileDialog();
            ofdSourceImage.Filter = "所有图像文件 | *.bmp; *.pcx; *.png; *.jpg; *.gif;" +
                "*.tif; *.ico; *.dxf; *.cgm; *.cdr; *.wmf; *.eps; *.emf|" +
                "位图( *.bmp; *.jpg; *.png;...) | *.bmp; *.pcx; *.png; *.jpg; *.gif; *.tif; *.ico|" + "矢量图( *.wmf; *.eps; *.emf;...) | *.dxf; *.cgm; *.cdr; *.wmf; *.eps; *.emf";     //为图像创建筛选器
            //设置标题
            ofdSourceImage.Title = "打开图片";
            //关闭帮助按钮
            ofdSourceImage.ShowHelp = false;
            
            //打开图像
            if (ofdSourceImage.ShowDialog() == DialogResult.OK)
            {
                strSourceImage = ofdSourceImage.FileName;
                bmpSourceImage = (Bitmap)Image.FromFile(strSourceImage);
                if (bmpSourceImage.Width == 512 && bmpSourceImage.Height == 512 && bmpSourceImage.PixelFormat == PixelFormat.Format8bppIndexed)
                {
                    pbSourceImage.Image = bmpSourceImage;
                    tabControl1.SelectedIndex = 1;
                }
                else
                {
                    MessageBox.Show( "该demo版本只支持512*512的8位图像，请重新选择!","提示：");
                }
                
            }
        }



        //生成二维码
        private void btnCreateDM_Click(object sender, EventArgs e)
        {
            if (this.tbInfo.Text != String.Empty)
            {
                DataMatrix DMCreater = new DataMatrix();
                int result = DMCreater.CreateCode(this.tbInfo.Text.ToString());
                if (result != -1)
                {
                    if (result <= 22)
                    {
                        sBarcode = new string(DMCreater.cBarcode);
                        tbBinary.Text = DMCreater.sBarcode;

                        //生成二维码图片
                        pbDM.Image = (Bitmap)DMCreater.bmpBarcode;
                        bmpDM = DMCreater.bmpBarcode;

                        //生成要嵌入的信息流
                        char[] cTmp = DMCreater.cBarcode;
                        double sum = 0;
                        for (int i = 0; i < cTmp.Length; i++)
                        {
                            dInfo[i] = (double)(int)cTmp[i] ;
                            sum += dInfo[i];
                        }

                       // int d;
                    }
                    else
                    {
                        MessageBox.Show("您输入的信息长度超过限制，请缩减后重新输入！", "状态");
                    }
                    label4.Text = "字符长度：" + sBarcode.Length;
                }
                else
                {
                    MessageBox.Show("编码失败！", "状态：");
                }
            }
            else
            {
                MessageBox.Show("您还没有输入信息，请输入！", "提示：", MessageBoxButtons.OK);
            }
            tabControl1.SelectedIndex = 0;
            
        }


        //嵌入水印信息
        private void btnInsert_Click(object sender, EventArgs e)
        {
            if (bmpSourceImage != null && dInfo!=null)
            {
                //位图矩形
                Rectangle rect = new Rectangle(0, 0, bmpSourceImage.Width, bmpSourceImage.Height);
                //以可读写的方式锁定全部位图像素
                System.Drawing.Imaging.BitmapData bmpSourceData = bmpSourceImage.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, bmpSourceImage.PixelFormat);
                //获得首地址
                IntPtr ptr = bmpSourceData.Scan0;

                //定义源图像的数据数组
                int bytes = bmpSourceData.Width * bmpSourceData.Height;
                byte[] bmpSourceBytes = new byte[bytes];
                //复制被锁定的位图像素值到该数组内
                System.Runtime.InteropServices.Marshal.Copy(ptr, bmpSourceBytes, 0, bytes);
                bmpSourceImage.UnlockBits(bmpSourceData);

                //图像分割
                //将图像数据等分为64*64块
                bBmpBlocks = ImageCut(bmpSourceBytes);

                //傅里叶变换
               for (int i = 0; i < num*num ; i++)
               {
                   byte[] byteTmp = new byte[BLOCKS_SIDE_LEN  * BLOCKS_SIDE_LEN];
                   Complex[] compTmp = new Complex[BLOCKS_SIDE_LEN * BLOCKS_SIDE_LEN];
                   for (int j = 0; j < BLOCKS_SIDE_LEN * BLOCKS_SIDE_LEN; j++)
                   {
                       byteTmp[j] = bBmpBlocks[i, j];
                   }
                   compTmp = FourierTranform.fft2(byteTmp, BLOCKS_SIDE_LEN, BLOCKS_SIDE_LEN, true);
                   for (int j = 0; j < BLOCKS_SIDE_LEN * BLOCKS_SIDE_LEN; j++)
                   {
                       cpxBmpBlocks[i, j] = compTmp[j];
                   }
                
               }

                //嵌入
               InsertWM(dInfo,ref cpxBmpBlocks);

                //逆变换
               for (int i = 0; i < num*num; i++)
               {
                   Complex[] cpxTmp = new Complex[num*num];
                   for (int j = 0; j < BLOCKS_SIDE_LEN *BLOCKS_SIDE_LEN ; j++)
                   {
                       cpxTmp[j] = cpxBmpBlocks[i, j];
                   }

                   byte[] byteTmp = new byte[BLOCKS_SIDE_LEN *BLOCKS_SIDE_LEN ];
                   byteTmp = FourierTranform.ifft2(cpxTmp, BLOCKS_SIDE_LEN , BLOCKS_SIDE_LEN , true);
                   for (int j = 0; j < BLOCKS_SIDE_LEN *BLOCKS_SIDE_LEN ; j++)
                   {
                       bBmpBlocks[i, j] = byteTmp[j];
                   }

               }


                //把分块数据合并到一起
               byte[] byteInsertedImage = new byte[IMAGE_SIDE_LEN * IMAGE_SIDE_LEN];
               byteInsertedImage = ImageMerge(bBmpBlocks);
                 
                //重新生成图像
               Rectangle rect1 = new Rectangle(0, 0, IMAGE_SIDE_LEN, IMAGE_SIDE_LEN);
                bmpInsertedImage = new Bitmap(IMAGE_SIDE_LEN, IMAGE_SIDE_LEN, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
                System.Drawing.Imaging.BitmapData bmpInsertedData = bmpInsertedImage.LockBits(rect1, ImageLockMode.ReadWrite, bmpInsertedImage.PixelFormat);
                IntPtr ptrInserted = bmpInsertedData.Scan0;
                System.Runtime.InteropServices.Marshal.Copy(byteInsertedImage, 0, ptrInserted, IMAGE_SIDE_LEN * IMAGE_SIDE_LEN);
                bmpInsertedImage.UnlockBits(bmpInsertedData);
                bmpInsertedImage.Palette = bmpSourceImage.Palette;
                pbInsertedImage.Image = bmpInsertedImage;
                tabControl1.SelectedIndex = 2;
            }
            else
            {
                if (bmpSourceImage != null)
                {
                    MessageBox.Show("您还没有输入水印信息，请输入", "提示：", MessageBoxButtons.OK);
                    tabControl1.SelectedIndex = 0;
                }
                else
                {
                    MessageBox.Show("您还没有选择图片，请选择图片。", "提示：", MessageBoxButtons.OK);
                    tabControl1.SelectedIndex = 1;
                }
            }
        }

        /**************************************************
         * 图像分割
         * bmpSourceBytes:源图像数据
         * ************************************************/
        private static byte[,] ImageCut(byte[] bmpSourceBytes)
        {
            byte[,] bmpBytes = new byte[num * num, 512 / num * 512 / num];
            for (int y = 0; y < num; y++)
            {
                for (int x = 0; x < num; x++)
                {
                    for (int j = y * BLOCKS_SIDE_LEN  ; j < (y + 1) * BLOCKS_SIDE_LEN ; j++)
                    {
                        for (int i = x * BLOCKS_SIDE_LEN  ; i < (x + 1) * BLOCKS_SIDE_LEN  ; i++)
                        {
                            bmpBytes[num * x + y, i % BLOCKS_SIDE_LEN  * BLOCKS_SIDE_LEN  + j % BLOCKS_SIDE_LEN ] = bmpSourceBytes[i * IMAGE_SIDE_LEN + j];
                        }
                    }
                }
            }

            return bmpBytes;

        }

        /*****************************************************************************
         * 合并分块图像数据
         * **************************************************************************/
        private static byte[] ImageMerge(byte[,] bmpBytes)
        {
            byte[] byteInsertedBmp = new byte[IMAGE_SIDE_LEN * IMAGE_SIDE_LEN];
            for (int y = 0; y < num; y++)
            {
                for (int x = 0; x < num; x++)
                {
                    for (int j = y * BLOCKS_SIDE_LEN; j < (y + 1) * BLOCKS_SIDE_LEN; j++)
                    {
                        for (int i = x * BLOCKS_SIDE_LEN; i < (x + 1) * BLOCKS_SIDE_LEN; i++)
                        {
                            byteInsertedBmp[i * IMAGE_SIDE_LEN + j] = bmpBytes[num * x + y, i % BLOCKS_SIDE_LEN * BLOCKS_SIDE_LEN + j % BLOCKS_SIDE_LEN];
                        }
                    }
                }
            }

            return byteInsertedBmp;
        }



        /*******************************************************
         * 嵌入水印
         * byte[] byteWM :需要嵌入的水印信息
         * ref Complex[] :需要嵌入水印的载体
         * ***********************************************/
        private static void InsertWM(double[] dInfo,  ref Complex[,] cpxBmp)
        {
            //嵌入强度
            double r = 1;

            for (int i = 0; i < 512; i++) 
            {
                cpxBmp[i, 7 * 0].Re  = r * (double)dInfo[i];
            }
        }

        /**************************************************************
         * 提取水印
         *************************************************************/
        private static void GetWM(Complex[,] cpxBmp, ref double[] dInfo)
        {
            //提取阀值
            double t = 0.5;

            for (int i = 0; i < 512; i++)
            {
                if (cpxBmp[i, 0].Re > t)
                {
                    dInfo[i] = 1;
                }
                else
                {
                    dInfo[i] = 0;
                }
            }
        }

        //提取水印信息
        private void btnGetWM_Click(object sender, EventArgs e)
        {
            tabControl1.SelectedIndex = 3;
            ////读取嵌入水印的图片，如果图片都没有打开，则提示打开图片
            if (bmpInsertedImage != null || bmpSourceImage != null)
            {
                //如果是验证刚刚嵌入的图片，则处理bmpInsertedImage图片，否则处理重新打开的图片
                if (bmpInsertedImage != null)
                {
                    bmpSourceImage = bmpInsertedImage;
                }
                Rectangle rect = new Rectangle(0, 0, IMAGE_SIDE_LEN, IMAGE_SIDE_LEN);
                System.Drawing.Imaging.BitmapData bmpData = bmpSourceImage.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);
                IntPtr ptr = bmpData.Scan0;

                int bytes = IMAGE_SIDE_LEN * IMAGE_SIDE_LEN;
                byte[] bmpSourceBytes = new byte[bytes];
                System.Runtime.InteropServices.Marshal.Copy(ptr, bmpSourceBytes, 0, bytes);
                bmpSourceImage.UnlockBits(bmpData);
                //图像分割
                bBmpBlocks = ImageCut(bmpSourceBytes);
                //傅里叶变换
                for (int i = 0; i < num * num; i++)
                {
                    byte[] byteTmp = new byte[BLOCKS_SIDE_LEN * BLOCKS_SIDE_LEN];
                    Complex[] compTmp = new Complex[BLOCKS_SIDE_LEN * BLOCKS_SIDE_LEN];
                    for (int j = 0; j < BLOCKS_SIDE_LEN * BLOCKS_SIDE_LEN; j++)
                    {
                        byteTmp[j] = bBmpBlocks[i, j];
                    }
                    compTmp = FourierTranform.fft2(byteTmp, BLOCKS_SIDE_LEN, BLOCKS_SIDE_LEN, true);
                    for (int j = 0; j < BLOCKS_SIDE_LEN * BLOCKS_SIDE_LEN; j++)
                    {
                        cpxBmpBlocks[i, j] = compTmp[j];
                    }
                }

                double[] dTmp = new double[512];
                //提取水印信息
                GetWM(cpxBmpBlocks, ref dTmp);

                double sum = 0;
                for (int i = 0; i < 22 * 22; i++)
                {
                    dGetInfo[i] = dTmp[i];
                    sum += dGetInfo[i];
                }
                //解码水印信息
                DataMatrix DM = new DataMatrix();
                //string strBinary = null;

                string strGetInfo = DM.ReadCode(dGetInfo);
                tbGetInfo.Text = strGetInfo;
                pbGetDM.Image = DM.bmpBarcode;
                bmpGetDM = DM.bmpBarcode;
                tbGetBinary.Text = DM.sBarcode;
                tabControl1.SelectedIndex = 3;
              
            }
            else
            {
                MessageBox.Show("请打开图片！", "提示", MessageBoxButtons.OK);
            }
        }

        private void btnSaveImage_Click(object sender, EventArgs e)
        {
            string file_save;
            SaveFileDialog dlg_save = new SaveFileDialog();
            dlg_save.Title = "保存图形为";
            dlg_save.OverwritePrompt = true;
            dlg_save.Filter = "BMP文件(*.bmp)|*.bmp|" + "GIF文件(*.gif)|*.gif|" +
                "JPEG文件(*.jpg)|*.jpg";
            dlg_save.ShowHelp = false;
            if (bmpInsertedImage != null)
            {
                if (dlg_save.ShowDialog() == DialogResult.OK)
                {
                    file_save = dlg_save.FileName;
                    string strFileExtn = file_save.Remove(0, file_save.Length - 3);

                    //保存文件
                    switch (strFileExtn)
                    {
                        case "bmp":
                            //bmp格式
                            bmpInsertedImage.Save(file_save, System.Drawing.Imaging.ImageFormat.Bmp);
                            break;
                        case "gif":
                            //gif格式
                            bmpInsertedImage.Save(file_save, System.Drawing.Imaging.ImageFormat.Gif);
                            break;
                        case "jpg":
                            //jpg格式
                            bmpInsertedImage.Save(file_save, System.Drawing.Imaging.ImageFormat.Jpeg);
                            break;
                        default:
                            break;
                    }
                }
 
            }
            

            
        }

        private void btnSaveDM_Click(object sender, EventArgs e)
        {
            string file_save;
            SaveFileDialog dlg_save = new SaveFileDialog();
            dlg_save.Title = "保存图形为";
            dlg_save.OverwritePrompt = true;
            dlg_save.Filter = "BMP文件(*.bmp)|*.bmp|" + "GIF文件(*.gif)|*.gif|" +
                "JPEG文件(*.jpg)|*.jpg";
            dlg_save.ShowHelp = false;
            if (bmpDM != null)
            {
                if (dlg_save.ShowDialog() == DialogResult.OK)
                {
                    file_save = dlg_save.FileName;
                    string strFileExtn = file_save.Remove(0, file_save.Length - 3);

                    //保存文件
                    switch (strFileExtn)
                    {
                        case "bmp":
                            //bmp格式
                            bmpDM.Save(file_save, System.Drawing.Imaging.ImageFormat.Bmp);
                            break;
                        case "gif":
                            //gif格式
                            bmpDM.Save(file_save, System.Drawing.Imaging.ImageFormat.Gif);
                            break;
                        case "jpg":
                            //jpg格式
                            bmpDM.Save(file_save, System.Drawing.Imaging.ImageFormat.Jpeg);
                            break;
                        default:
                            break;
                    }
                }

            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string file_save;
            SaveFileDialog dlg_save = new SaveFileDialog();
            dlg_save.Title = "保存图形为";
            dlg_save.OverwritePrompt = true;
            dlg_save.Filter = "BMP文件(*.bmp)|*.bmp|" + "GIF文件(*.gif)|*.gif|" +
                "JPEG文件(*.jpg)|*.jpg";
            dlg_save.ShowHelp = false;
            if (bmpGetDM != null)
            {
                if (dlg_save.ShowDialog() == DialogResult.OK)
                {
                    file_save = dlg_save.FileName;
                    string strFileExtn = file_save.Remove(0, file_save.Length - 3);

                    //保存文件
                    switch (strFileExtn)
                    {
                        case "bmp":
                            //bmp格式
                            bmpGetDM.Save(file_save, System.Drawing.Imaging.ImageFormat.Bmp);
                            break;
                        case "gif":
                            //gif格式
                            bmpGetDM.Save(file_save, System.Drawing.Imaging.ImageFormat.Gif);
                            break;
                        case "jpg":
                            //jpg格式
                            bmpGetDM.Save(file_save, System.Drawing.Imaging.ImageFormat.Jpeg);
                            break;
                        default:
                            break;
                    }
                }

            }
        }
    }
}
